#include "drv_usb_hw.h"
#include "cdc_acm_core.h"
#include "gd32h759i_eval.h"
#include "system_gd32h7xx.h"
#include <stdio.h>
#include <string.h>

// USB核心驱动实例
usb_core_driver cdc_acm;

// 通信统计配置与变量
#define COMM_STOP_DELAY     2000U    // 通信停止判断阈值(ms)
#define USER_DATA_MIN_LEN   1U       // 最小有效数据长度(字节)
volatile uint32_t systick_counter = 0;  // 毫秒计数器
uint32_t start_time = 0;                // 通信开始时间(ms)
uint32_t last_comm_time = 0;            // 最后一次通信时间(ms)
uint32_t total_frames = 0;              // 总用户数据帧数
uint32_t current_window_frames = 0;     // 当前统计窗口内的帧数
uint32_t window_start_time = 0;         // 当前统计窗口的开始时间
uint32_t max_fps = 0;                   // 最大帧率
FlagStatus is_communicating = RESET;    // 通信状态标志
FlagStatus has_new_data = RESET;        // 新数据标志

// 函数声明
void cache_enable(void);
void usart_init(void);
uint32_t get_current_time(void);
void check_comm_stop(void);
void update_comm_stats(void);
void calculate_final_stats(void);
void systick_config(void);
int fputc(int ch, FILE *f);
void user_data_receive_hook(uint8_t *data, uint32_t len);

/*!
    \brief      启用CPU缓存
*/
void cache_enable(void)
{
    SCB_EnableICache();
#ifndef USB_INTERNAL_DMA_ENABLED
    SCB_EnableDCache();
#endif
}

/*!
    \brief      初始化USART用于统计打印
*/
void usart_init(void)
{
    gd_eval_com_init(EVAL_COM);  // 评估板默认串口
    gd_eval_led_init(LED2);
    gd_eval_led_off(LED2);
}

/*!
    \brief      获取当前时间（毫秒）
*/
uint32_t get_current_time(void)
{
    return systick_counter;
}

/*!
    \brief      检查通信是否停止
*/
void check_comm_stop(void)
{
    if(is_communicating == SET) {
        uint32_t current_time = get_current_time();
        if((current_time - last_comm_time) >= COMM_STOP_DELAY) {
            calculate_final_stats();
            
            uint32_t total_time = last_comm_time - start_time;
            if(total_time == 0) total_time = 1;
            
            printf("\r\n===== 通信结束统计 =====");
            printf("\r\n总通信时间: %d ms (%.2f 秒)", 
                   total_time, total_time / 1000.0f);
            printf("\r\n总用户数据帧数: %d 帧", total_frames);
            printf("\r\n平均帧率: %.1f 帧/秒", 
                   (float)total_frames / (total_time / 1000.0f));
            printf("\r\n最大帧率: %d 帧/秒", max_fps);
            printf("\r\n========================\r\n");
            printf("等待用户数据...\r\n");

            // 重置统计变量
            is_communicating = RESET;
            total_frames = 0;
            max_fps = 0;
            start_time = 0;
            current_window_frames = 0;
            window_start_time = 0;
            gd_eval_led_off(LED2);
        }
    }
}

/*!
    \brief      通信结束时计算最后一段的帧率
*/
void calculate_final_stats(void)
{
    if(current_window_frames > 0) {
        uint32_t window_duration = last_comm_time - window_start_time;
        if(window_duration == 0) window_duration = 1;
        
        uint32_t fps = (current_window_frames * 1000) / window_duration;
        if(fps > max_fps) {
            max_fps = fps;
        }
        printf("\r\n[结束前统计] 最后 %.1f 秒内帧率: %d 帧/秒",
               window_duration / 1000.0f, fps);
    }
}

/*!
    \brief      更新通信统计
*/
void update_comm_stats(void)
{
    uint32_t current_time = get_current_time();
    
    if(is_communicating == RESET) {
        is_communicating = SET;
        start_time = current_time;
        last_comm_time = current_time;
        window_start_time = current_time;
        current_window_frames = 0;
        max_fps = 0;
        printf("\r\n===== 检测到用户数据，开始实时统计 =====");
        gd_eval_led_on(LED2);
    }

    last_comm_time = current_time;
    total_frames++;
    current_window_frames++;

    // 每1秒打印一次实时帧率
    if((current_time - window_start_time) >= 1000U) {
        uint32_t fps = current_window_frames;
        if(fps > max_fps) {
            max_fps = fps;
        }
        printf("\r\n[实时统计] 已通信 %.1f 秒 - 帧率: %d 帧/秒 (累计: %d 帧)",
               (current_time - start_time)/1000.0f, fps, total_frames);
        
        window_start_time = current_time;
        current_window_frames = 0;
        gd_eval_led_toggle(LED2);
    }
}

/*!
    \brief      重定向printf到USART
*/
int fputc(int ch, FILE *f)
{
    usart_data_transmit(EVAL_COM, (uint8_t)ch);
    while(RESET == usart_flag_get(EVAL_COM, USART_FLAG_TBE));
    return ch;
}

/*!
    \brief      配置SysTick定时器（1ms中断）
*/
void systick_config(void)
{
    if(SysTick_Config(SystemCoreClock / 1000U)) {
        while(1);
    }
    NVIC_SetPriority(SysTick_IRQn, 0x0FU);
}

/*!
    \brief      SysTick中断服务程序（毫秒计数）
*/
void SysTick_Handler(void)
{
    systick_counter++;
}

/*!
    \brief      用户数据接收钩子函数
*/
void user_data_receive_hook(uint8_t *data, uint32_t len)
{
    // 只要数据长度符合要求，就视为有效帧并计数
    if(len >= USER_DATA_MIN_LEN) {
        last_comm_time = get_current_time();
        has_new_data = SET;  // 所有符合长度的数据包都触发统计更新
    }
}

/*!
    \brief      主函数
*/
int main(void)
{
    cache_enable();
    usart_init();
    systick_config();

    printf("USB虚拟串口就绪！请通过串口助手(COM11)发送数据...\r\n");

    // USB初始化
    usb_rcu_config();
    usb_timer_init();

#ifdef USE_USBHS0
#ifdef USE_USB_FS
    usb_para_init(&cdc_acm, USBHS0, USB_SPEED_FULL);
#endif
#ifdef USE_USB_HS
    usb_para_init(&cdc_acm, USBHS0, USB_SPEED_HIGH);
#endif
#endif

#ifdef USE_USBHS1
#ifdef USE_USB_FS
    usb_para_init(&cdc_acm, USBHS1, USB_SPEED_FULL);
#endif
#ifdef USE_USB_HS
    usb_para_init(&cdc_acm, USBHS1, USB_SPEED_HIGH);
#endif
#endif

    usbd_init(&cdc_acm, &cdc_desc, &cdc_class);

#ifdef USE_USB_HS
#ifndef USE_ULPI_PHY
#ifdef USE_USBHS0
    pllusb_rcu_config(USBHS0);
#elif defined USE_USBHS1
    pllusb_rcu_config(USBHS1);
#endif
#endif
#endif

    usb_intr_config();

    // 主循环
    while(1) {
        if(USBD_CONFIGURED == cdc_acm.dev.cur_status) {
            if(0U == cdc_acm_check_ready(&cdc_acm)) {
                cdc_acm_data_receive(&cdc_acm);
            } else {
                cdc_acm_data_send(&cdc_acm);
            }

            if(has_new_data) {
                update_comm_stats();
                has_new_data = RESET;
            }
        }
        check_comm_stop();
    }
}
    